////////////////////////////////////////////////////////////////////////////
//
//  Crytek Engine Source File.
//  Copyright (C), Crytek Studios, 2002.
// -------------------------------------------------------------------------
//  File name:   brushplane.cpp
//  Version:     v1.00
//  Created:     9/7/2002 by Timur.
//  Compilers:   Visual Studio.NET
//  Description: 
// -------------------------------------------------------------------------
//  History:
//	06/04/2007 Refactored by Jaesik
////////////////////////////////////////////////////////////////////////////

#include "StdAfx.h"
#include "BrushPlane.h"

#define VER_EPS 0.01f

static Vec3 s_baseAxis[] =
{
	Vec3(0,0,1),   Vec3(1,0,0),  Vec3(0,-1,0),  // floor
	Vec3(0,0,-1),  Vec3(-1,0,0), Vec3(0,1,0),   // ceiling
	Vec3(1,0,0),   Vec3(0,1,0),  Vec3(0,0,-1),  // west wall
	Vec3(-1,0,0),  Vec3(0,-1,0), Vec3(0,0,-1),  // east wall
	Vec3(0,1,0),   Vec3(-1,0,0), Vec3(0,0,-1),	// south wall
	Vec3(0,-1,0),  Vec3(1,0,0),  Vec3(0,0,-1),  // north wall
};


void SBrushPlane::CreatePoly( std::vector<Vec3>& outputlist )
{
	int   i, x;
	float max, v;
	Vec3 org, vright, vup;

	if( !outputlist.empty() )
		outputlist.clear();

	max = -99999;
	x = -1;
	for (i=0 ; i<3; ++i)
	{
		v = (float)fabs(normal[i]);
		if (v > max)
		{
			x = i;
			max = v;
		}
	}
	if (x==-1)
	{
		CLogFile::WriteLine("Error: SBrushPlane::CreatePoly: no axis found");
		return;
	}

	vup(0,0,0);
	if (x != 2)
		vup = Vec3(0,0,1);
	else
		vup = Vec3(1,0,0);

	v = normal | vup;
	vup += normal * (-v);
	vup.Normalize();

	org = normal * (-distance);
	vright = normal ^ vup;

	vup *= 32768.0f;
	vright *= 32768.0f;

	Vec3 pt;
	pt = org - vright;
	pt += vup;
	outputlist.push_back(pt);

	pt = org + vright;
	pt += vup;
	outputlist.push_back(pt);

	pt = org + vright;
	pt -= vup;
	outputlist.push_back(pt);

	pt = org - vright;
	pt -= vup;
	outputlist.push_back(pt);
}


bool SBrushPlane::ClipByPlane( const SBrushPlane& split, const std::vector<Vec3>& inputlist, std::vector<Vec3>& outputlist )
{
	int inputsize = (int)inputlist.size();
	std::vector<char> sign;
	sign.resize(inputsize);

	float dot_result = fabs(split.normal.dot(normal));

	if( dot_result > 0.9999999f )
		return false;

	if( !outputlist.empty() )
		outputlist.clear();

	for( int i = 0; i < inputsize; ++i )
	{
		float dist = split.Distance(inputlist[i]);

		if( dist > VER_EPS )
		{
			sign[i] = 1;
		}
		else if( dist < -VER_EPS )
		{
			sign[i] = -1;
		}
		else
		{
			sign[i] = 0;
		}
	}

	for( int i = 0; i < inputsize; ++i )
	{
		int nexti = (i+1)%inputsize;
		const Vec3& p0 = inputlist[i];

		if( sign[i] == 0 )
		{
			outputlist.push_back(p0);
			continue;
		}

		if( sign[i] == -1 )
			outputlist.push_back(p0);

		if( sign[nexti] == 0 || sign[i] == sign[nexti] )
			continue;

		const Vec3& p1 = inputlist[nexti];

		Vec3 p01;
		if( split.HitTest( p0, p1, NULL, &p01 ) )
			outputlist.push_back(p01);
	}

	return true;
}


bool SBrushPlane::HitTest( const Vec3& p0, const Vec3& p1, float* tout, Vec3* vout, const float epsilon  ) const
{
	float denominator = (normal|(p1-p0));

	if( fabs(denominator) < epsilon )
		return false;

	float t = -((normal|p0)+distance)/denominator;

	if( tout )
		*tout = t; 

	if( vout )
		*vout = p0 + t * (p1 - p0);

	return true;
}


void SBrushPlane::CalcTextureAxis(Vec3& xv, Vec3& yv) const
{
	size_t  bestaxis;
	float		dot,best;	

	best = -1;
	bestaxis = 0;

	for( size_t i(0) ; i<6 ; ++i)
	{
		dot = normal.Dot( s_baseAxis[i*3] );
		if (dot > best)
		{
			best = dot;
			bestaxis = i;
		}
	}

	xv = s_baseAxis[bestaxis*3+1];
	yv = s_baseAxis[bestaxis*3+2];
}